﻿using Microsoft.Xna.Framework;
using System;
using Terraria;
using Terraria.Audio;
using Terraria.DataStructures;
using Terraria.GameContent.Bestiary;
using Terraria.ID;
using Terraria.ModLoader;

namespace HardcoreGame.Content.NPCs.Enemies.Biomesa.Desert
{
    public class SandJerboa : ModNPC
    {
        private enum AIState
        {
            Idle,
            Jumping,
            Attacking,
            Stunned
        }
        private ref float State => ref NPC.ai[0];
        private ref float Timer => ref NPC.ai[1];
        private ref float JumpPower => ref NPC.ai[2];
        private ref float AttackCooldown => ref NPC.ai[3];
        private const float MAX_JUMP_POWER = 12f;
        private const float JUMP_ACCELERATION = 0.3f;
        private const int ATTACK_DAMAGE = 12;
        private const int ATTACK_COOLDOWN = 300;

        public override void SetStaticDefaults()
        {
            Main.npcFrameCount[Type] = 4;
        }

        public override void SetDefaults()
        {
            NPC.width = 32;
            NPC.height = 24;
            NPC.damage = ATTACK_DAMAGE;
            NPC.defense = 4;
            NPC.lifeMax = 45;
            NPC.HitSound = SoundID.NPCHit1;
            NPC.DeathSound = SoundID.NPCDeath1;
            NPC.value = 30f;
            NPC.knockBackResist = 0.5f;
            NPC.aiStyle = 0;
            NPC.noGravity = false;
            NPC.noTileCollide = false;
            NPC.rarity = (int)0.2f;
        }

        public override void AI()
        {
            NPC.TargetClosest(true);
            Player target = Main.player[NPC.target];
            switch ((AIState)State)
            {
                case AIState.Idle:
                    UpdateIdleState(target);
                    break;

                case AIState.Jumping:
                    UpdateJumpingState(target);
                    break;

                case AIState.Attacking:
                    UpdateAttackingState(target);
                    break;

                case AIState.Stunned:
                    UpdateStunnedState();
                    break;
            }
            UpdateAnimation();
        }

        private void UpdateIdleState(Player target)
        {
            NPC.spriteDirection = NPC.direction = target.Center.X > NPC.Center.X ? 1 : -1;
            Timer++;
            if (Timer >= 60)
            {
                Timer = 0;
                State = (float)AIState.Jumping;
                JumpPower = 0;
            }
        }

        private void UpdateJumpingState(Player target)
        {
            JumpPower += JUMP_ACCELERATION;
            if (JumpPower >= MAX_JUMP_POWER)
            {
                float xDist = target.Center.X - NPC.Center.X;
                float yDist = target.Center.Y - NPC.Center.Y;
                float velX = MathHelper.Clamp(xDist / 16f, -6f, 6f);
                float velY = -JumpPower;
                if (Math.Abs(xDist) > 120)
                {
                    velX *= 1.2f;
                    velY *= 0.9f;
                }
                NPC.velocity.X = velX;
                NPC.velocity.Y = velY;
                SoundEngine.PlaySound(SoundID.Item17, NPC.Center);
                State = (float)AIState.Attacking;
                Timer = 0;
            }
        }

        private void UpdateAttackingState(Player target)
        {
            Timer++;
            if (NPC.collideY)
            {
                if (Timer < 10)
                {
                    Rectangle attackRect = new(
                        (int)(NPC.position.X - 16),
                        (int)(NPC.position.Y - 16),
                        NPC.width + 32,
                        NPC.height + 16
                    );

                    if (target.Hitbox.Intersects(attackRect))
                    {
                        target.Hurt(PlayerDeathReason.ByNPC(NPC.whoAmI), ATTACK_DAMAGE, NPC.direction);
                    }
                }
                State = (float)AIState.Idle;
                AttackCooldown = ATTACK_COOLDOWN;
            }
        }

        private void UpdateStunnedState()
        {
            Timer--;
            if (Timer <= 0)
            {
                State = (float)AIState.Idle;
            }
        }

        public override void OnHitByItem(Player player, Item item, NPC.HitInfo hit, int damageDone)
        {
            ApplyStun(hit.Knockback);
        }

        public override void OnHitByProjectile(Projectile projectile, NPC.HitInfo hit, int damageDone)
        {
            ApplyStun(hit.Knockback);
        }

        private void ApplyStun(float knockback)
        {
            if (knockback > 2f)
            {
                State = (float)AIState.Stunned;
                Timer = knockback * 5;
            }
        }

        private void UpdateAnimation()
        {
            if (NPC.velocity.Y != 0)
            {
                NPC.frame.Y = 2 * NPC.frame.Height;
            }
            else if ((AIState)State == AIState.Jumping)
            {
                NPC.frame.Y = 1 * NPC.frame.Height;
            }
            else if ((AIState)State == AIState.Attacking && Timer < 5)
            {
                NPC.frame.Y = 3 * NPC.frame.Height;
            }
            else
            {
                NPC.frameCounter++;
                if (NPC.frameCounter >= 10)
                {
                    NPC.frameCounter = 0;
                }
            }
        }

        public override float SpawnChance(NPCSpawnInfo spawnInfo)
        {
            if (spawnInfo.Player.ZoneDesert && spawnInfo.SpawnTileY < Main.worldSurface && !Main.dayTime)
            {
                return 0.2f;
            }
            return 0f;
        }
        public override void SetBestiary(BestiaryDatabase database, BestiaryEntry bestiaryEntry)
        {
            bestiaryEntry.Info.AddRange([
                BestiaryDatabaseNPCsPopulator.CommonTags.SpawnConditions.Biomes.Desert,
                new FlavorTextBestiaryInfoElement("Mods.HardcoreGame.NPCs.SandJerboa.Bestiary")
            ]);
        }
    }
}